package com.hermes.comics;

import android.app.Activity;
import android.app.ActionBar;
import android.app.ListActivity;

import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.content.res.Resources;

import android.os.Bundle;

import android.speech.RecognizerIntent;

import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.view.GravityCompat;

import android.text.Html;
import android.text.Spanned;
import android.text.TextUtils;

import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;

import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.ExpandableListView;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SearchView;
import android.widget.SimpleExpandableListAdapter;
import android.widget.TextView;
import android.widget.Toast;

import com.hermes.comics.data.Catalog;
import com.hermes.comics.data.Constants;
import com.hermes.comics.data.Issue;
import com.hermes.comics.data.IssueTag;
import com.hermes.comics.data.Serie;
import com.hermes.comics.data.SerieGroup;
import com.hermes.comics.data.SerieTag;
import com.hermes.comics.dialogs.AutoUpdateSerieDialog;
import com.hermes.comics.dialogs.EditSerieFieldDialog;
import com.hermes.comics.dialogs.RefreshCatalogDialog;
import com.hermes.comics.dialogs.SaveItemDialog;
import com.hermes.comics.utils.ImageUtils;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class MainActivity extends Activity
    implements SearchView.OnQueryTextListener, ExpandableListView.OnChildClickListener, AdapterView.OnItemClickListener {

  private static final int RESULT_SPEECH = 1;

  private int listPosition = 0;
  private static SerieGroup serieGroup = null;

  private SearchView searchView;
  private ActionBarDrawerToggle drawerToggle;
  private SimpleExpandableListAdapter serieGroupAdapter;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    Catalog.init(this);

    ActionBar actionBar = getActionBar();
    actionBar.setDisplayHomeAsUpEnabled(true);
    actionBar.setDisplayShowTitleEnabled(true);
    actionBar.setDisplayUseLogoEnabled(true);
    actionBar.setHomeButtonEnabled(true);

    boolean success = Catalog.getInstance().load();
    if (!success) {
      Toast.makeText(this, getString(R.string.database_not_found), Toast.LENGTH_LONG);
      new RefreshCatalogDialog(this).show();
    }

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer);
    drawerToggle = new ActionBarDrawerToggle(this, drawer,
      R.drawable.ic_drawer, R.string.drawer_open, R.string.drawer_close) {
      @Override
      public void onDrawerOpened(View drawerView) {
      }
    };
    drawer.setDrawerListener(drawerToggle);
    drawer.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);

    getListView().setOnItemClickListener(this);
    registerForContextMenu(getListView());
  }

  @Override
  public void onPause() {
    super.onPause();
    listPosition = getListView().getFirstVisiblePosition();
  }

  @Override
  public void onResume() {
    super.onResume();

    getListView().setTextFilterEnabled(true);
    setGroup(serieGroup);

    if (searchView != null) {
      CharSequence query = searchView.getQuery();
      if (!TextUtils.isEmpty(query)) {
        getListView().setFilterText(query.toString());
      }
    }

    buildGroupsList();
  }

  @Override
  public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
    Serie serie = (Serie) view.getTag();
    Intent intent = new Intent(this, IssuesActivity.class);
    intent.putExtra(Constants.SERIE_KEY, SerieTag.KEY.value(serie));
    startActivity(intent);
  }

  public void setGroup(SerieGroup sg) {
    if (sg != serieGroup) {
      listPosition = 0;
    }

    this.serieGroup = sg;

    String subtitle = "";
    List<Serie> series;
    if (serieGroup == null) {
      series = Catalog.getInstance().getAllSeries();
      subtitle = "All series (" + series.size() + ")";
    } else {
      series = serieGroup.getCurrentSeries(this);
      subtitle = serieGroup.title(this) + ": " + serieGroup.getCurrentItem(this).display()
          + " (" + serieGroup.getCurrentSeries(this).size() + ")";
    }

    getActionBar().setSubtitle(subtitle);
    setListAdapter(new CustomArrayAdapter(this, series));

    getListView().setSelectionFromTop(listPosition, 0);
  }

  @Override
  public boolean onQueryTextSubmit(String query) {
    return false;
  }

  @Override
  protected void onPostCreate(Bundle savedInstanceState) {
    super.onPostCreate(savedInstanceState);
    // Sync the toggle state after onRestoreInstanceState has occurred.
    drawerToggle.syncState();
  }

  @Override
  public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);
    drawerToggle.onConfigurationChanged(newConfig);
  }

  @Override
  public boolean onQueryTextChange(String newText) {
    if (TextUtils.isEmpty(newText)) {
      getListView().clearTextFilter();
    } else {
      getListView().setFilterText(newText.toString());
    }
    return true;
  }

  @Override
  public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
    SerieGroup group = SerieGroup.GROUPS[groupPosition];
    group.setPosition(childPosition);
    setGroup(group);

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer);
    drawer.closeDrawers();

    return true;
  }

  @Override
  public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
    super.onCreateContextMenu(menu, v, menuInfo);

    getMenuInflater().inflate(R.menu.edit_serie_menu, menu);

    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
    if (info == null) return;

    Serie serie = getSerieByPosition(info.position);
    boolean isUnreviewed = "Y".equals(SerieTag.UNREVIEWED.value(serie));
    ((MenuItem) menu.findItem(R.id.menu_unreviewed)).setChecked(isUnreviewed);
  }

  @Override
  public boolean onContextItemSelected(MenuItem item) {
    AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();

    if (info == null) return false;

    Serie serie = (Serie) info.targetView.getTag();

    SaveItemDialog.OnSaveData onSaveData = new SaveItemDialog.OnSaveData() {
      @Override
      public void onSave() {
        ((BaseAdapter) MainActivity.this.getListAdapter()).notifyDataSetChanged();

        ExpandableListView listView = (ExpandableListView) findViewById(R.id.groups);
        List<Integer> expandedGroups = new ArrayList<Integer>();
        for (int i = 0; i < serieGroupAdapter.getGroupCount(); i++) {
          if (listView.isGroupExpanded(i)) {
            expandedGroups.add(i);
          }
        }
        buildGroupsList();
        for (Integer idx : expandedGroups) {
          listView.expandGroup(idx);
        }
      }
    };

    switch (item.getItemId()) {
      case R.id.menu_unreviewed:
        serie.setTag(SerieTag.UNREVIEWED, "Y".equals(SerieTag.UNREVIEWED.value(serie)) ? "N" : "Y");
        SaveItemDialog.buildForSerie(this, serie, onSaveData).show();
        return true;
      case R.id.menu_language:
        EditSerieFieldDialog.build(this, onSaveData, serie, SerieTag.LANGUAGE).show();
        return true;
      case R.id.menu_title:
        EditSerieFieldDialog.build(this, onSaveData, serie, SerieTag.TITLE).show();
        return true;
      case R.id.menu_note:
        EditSerieFieldDialog.build(this, onSaveData, serie, SerieTag.NOTE).show();
        return true;
      case R.id.menu_category:
        EditSerieFieldDialog.build(this, onSaveData, serie, SerieTag.CATEGORY).show();
        return true;
      case R.id.menu_publisher:
        EditSerieFieldDialog.build(this, onSaveData, serie, SerieTag.PUBLISHER).show();
        return true;
      case R.id.menu_author:
        EditSerieFieldDialog.build(this, onSaveData, serie, SerieTag.AUTHOR).show();
        return true;
      case R.id.menu_genre:
        EditSerieFieldDialog.build(this, onSaveData, serie, SerieTag.GENRE).show();
        return true;
      case R.id.menu_format:
        EditSerieFieldDialog.build(this, onSaveData, serie, SerieTag.FORMAT).show();
        return true;
      case R.id.menu_auto_update:
        new AutoUpdateSerieDialog(this, serie, (BaseAdapter) getListAdapter()).show();
        break;
    }

    return true;
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
    // Pass the event to ActionBarDrawerToggle, if it returns
    // true, then it has handled the app icon touch event
    if (drawerToggle.onOptionsItemSelected(item)) {
      return true;
    }

    switch (item.getItemId()) {
      case R.id.menu_voice_search:
        return startSpeechWidget();
      case R.id.menu_web_extraction:
        startActivity(new Intent(this, WebExtractionActivity.class));
        return true;
      case R.id.menu_load:
        new RefreshCatalogDialog(this).show();
        return true;
      default:
        return super.onOptionsItemSelected(item);
    }
  }

  @Override
  protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);

    // Identify and extract text from speech.
    if ((requestCode == RESULT_SPEECH) && (resultCode == RESULT_OK) && (data != null)) {
      ArrayList<String> text = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
      searchView.setQuery(text.get(0), true);
    }
  }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.main_action_bar_menu, menu);

    searchView = (SearchView) menu.findItem(R.id.menu_search).getActionView();
    searchView.setIconifiedByDefault(false);
    searchView.setSubmitButtonEnabled(false);
    searchView.setOnQueryTextListener(this);

    return super.onCreateOptionsMenu(menu);
  }

  private void setListAdapter(CustomArrayAdapter adapter) {
    ListView list = (ListView) findViewById(R.id.list);
    list.setAdapter(adapter);
  }

  private ListView getListView() {
    return (ListView) findViewById(R.id.list);
  }

  private BaseAdapter getListAdapter() {
    return (BaseAdapter) getListView().getAdapter();
  }

  private Serie getSerieByPosition(int position) {
    CustomArrayAdapter adapter = (CustomArrayAdapter) getListAdapter();
    return adapter.getSerie(position);
  }

  private void addGroup(List<Map<String, String>> groupData,
                        List<List<Map<String, String>>> listOfChildGroups,
                        final SerieGroup group) {
    groupData.add(new HashMap<String, String>() {{
        put("TITLE", group.title(MainActivity.this));
    }});
    listOfChildGroups.add(group.getGroups(this));
  }

  private void buildGroupsList() {
    ExpandableListView listView = (ExpandableListView) findViewById(R.id.groups);

    List<Map<String, String>> groupData = new ArrayList<Map<String, String>>();
    List<List<Map<String, String>>> listOfChildGroups = new ArrayList<List<Map<String, String>>>();

    for (SerieGroup group : SerieGroup.GROUPS) {
      addGroup(groupData, listOfChildGroups, group);
    }

    serieGroupAdapter = new SimpleExpandableListAdapter(this,
      groupData,
      android.R.layout.simple_expandable_list_item_1,
      new String[] { "TITLE" },
      new int[] { android.R.id.text1 },

      listOfChildGroups,
      android.R.layout.simple_expandable_list_item_2,
      new String[] { "TITLE", "SUBTITLE" },
      new int[] { android.R.id.text1, android.R.id.text2 }
    ) {
      @Override
      public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
        return super.getGroupView(groupPosition, isExpanded, convertView, parent);
      }
    };

    listView.setAdapter(serieGroupAdapter);
    listView.setOnChildClickListener(this);
    listView.expandGroup(0);
  }

  private boolean startSpeechWidget() {
    Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
    intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, "en-US");
    try {
      startActivityForResult(intent, RESULT_SPEECH);
    } catch (ActivityNotFoundException a) {
      Toast.makeText(this, "Ops! Your device doesn't support Speech to Text", Toast.LENGTH_LONG)
        .show();
    }
    return true;
  }

  // Adapters.
  public static class CustomArrayAdapter extends ArrayAdapter<Serie> {

    private static final int RES_ID = R.layout.serie_list_item;

    private final Activity activity;
    private final List<Serie> series;

    public CustomArrayAdapter(Activity activity, List<Serie> series) {
      super(activity, RES_ID, series);
      this.activity = activity;
      this.series = series;
    }

    private LayoutInflater getInflater() {
      return (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    Serie getSerie(int position) {
      return series.get(position);
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
      final Serie serie = Catalog.getInstance().getSerie(SerieTag.KEY.value(getItem(position)));

      View view = convertView;
      if (convertView == null) { 
        view = getInflater().inflate(RES_ID, parent, false);
      }
      view.setTag(serie);

      TextView titleView = (TextView) view.findViewById(R.id.title);
      titleView.setEllipsize(TextUtils.TruncateAt.MARQUEE);
      titleView.setText(SerieTag.TITLE.value(serie));

      TextView missingView = (TextView) view.findViewById(R.id.missing);
      TextView unreviewedView = (TextView) view.findViewById(R.id.unreviewed);

      if ("Y".equals(SerieTag.UNREVIEWED.value(serie))) {
        missingView.setVisibility(View.GONE);
        unreviewedView.setVisibility(View.VISIBLE);
      } else if (serie.missing().isEmpty()) {
        missingView.setVisibility(View.GONE);
        unreviewedView.setVisibility(View.GONE);
      } else {
        missingView.setVisibility(View.VISIBLE);
        unreviewedView.setVisibility(View.GONE);
      }

      TextView readView = (TextView) view.findViewById(R.id.read);
      if (serie.read().size() > 0) {
        readView.setVisibility(View.VISIBLE);
        readView.setBackgroundResource(
            serie.read().size() == serie.issues().size()
            ? R.drawable.rounded_corner_blue  // all read
            : R.drawable.rounded_corner_blue_light);  // some read
      } else {
        readView.setVisibility(View.GONE);
      }

      TextView subtitle = (TextView) view.findViewById(R.id.subtitle);
      subtitle.setText(getSubtitle(serie));

      TextView extra = (TextView) view.findViewById(R.id.extra);
      extra.setText(getExtra(serie));

      String imageUrl = IssueTag.IMG.value(serie.issues().get(0));
      ImageUtils.setImage(serie.issues().get(0), (ImageView) view.findViewById(R.id.image));

      return view;
    }

    private String getSubtitle(Serie serie) {
      StringBuffer sb = new StringBuffer();
      int count = serie.issues().size();
      sb.append(activity.getResources().getQuantityString(R.plurals.number_of_issues, count, count));

      if ("Y".equals(SerieTag.UNREVIEWED.value(serie))) {
        sb.append(", unreviewed");
      } else if (serie.missing().size() > 0) {
        sb.append(", " + serie.missing().size() + " missing (");
        String delimiter = "";
        for (Issue issue : serie.missing()) {
          sb.append(delimiter);
          sb.append(IssueTag.KEY.value(issue));
          delimiter = ", ";
        }
        sb.append(")");
      }
      return sb.toString();
    }

    private void saveInfo(StringBuilder sb, String label, Serie serie, SerieTag tag) {
      String value = tag.value(serie);
      if (!TextUtils.isEmpty(value)) {
        sb.append("<br><b>").append(label).append(": </b>").append(value.replace("|", ", "));
      }
    }

    private Spanned getExtra(Serie serie) {
      Resources res = activity.getResources();

      StringBuilder sb = new StringBuilder();

      int lang_id = res.getIdentifier(
          "language_" + SerieTag.LANGUAGE.value(serie), "string", activity.getPackageName());
      sb.append("<b>Language: </b>").append(res.getString(lang_id).toLowerCase());

      saveInfo(sb, "Authors", serie, SerieTag.AUTHOR);
      saveInfo(sb, "Format", serie, SerieTag.FORMAT);
      saveInfo(sb, "Genre", serie, SerieTag.GENRE);
      saveInfo(sb, "Publishers", serie, SerieTag.PUBLISHER);
      saveInfo(sb, "Categories", serie, SerieTag.CATEGORY);
      saveInfo(sb, "Note", serie, SerieTag.NOTE);

      return Html.fromHtml(sb.toString());
    }
  }
}
